﻿#include "csv_reader_impl.hh"
#include "../box/service_box.hh"
#include "../util/os_util.hh"
#include "../util/string_util.hh"
#include "../util/time_util.hh"
#include "../detail/lang_impl.hh"

#include <algorithm>

static kratos::util::CursorImpl NullCursor(nullptr);
static kratos::util::ResultImpl NullResult(nullptr, {}, false);

kratos::util::CsvLoaderImpl::CsvLoaderImpl() {}

kratos::util::CsvLoaderImpl::~CsvLoaderImpl() {}

auto kratos::util::CsvLoaderImpl::load(const std::string &file_path,
                                       std::size_t skip_line) -> bool {
  skip_line_ = skip_line;
  file_path_ = file_path;
  cur_lineno_ = 1;
  last_error_.assign("");
  last_update_ts_ = util::get_os_time_millionsecond();
  std::fstream ifs;
  ifs.open(file_path);
  if (!ifs) {
    return false;
  }
  bool result = false;
  try {
    if (!file_loaded_) {
      // 初始加载
      result = parse(ifs, &row_vec_);
      // 无论加载是否成功都需要能够进行后续的热加载
      file_loaded_ = true;
    } else {
      // 热加载
      result = parse(ifs, &new_vec_);
    }
  } catch (std::exception &e) {
    save_error(std::string("Unexpected exception:") + e.what());
    return false;
  }
  return result;
}

auto kratos::util::CsvLoaderImpl::check_and_switch() -> void {
  if (new_vec_.empty()) {
    return;
  }
  row_vec_.swap(new_vec_);
  new_vec_.clear();
}

auto kratos::util::CsvLoaderImpl::set_auto_reload(bool on_off) -> bool {
  auto old_flag = is_auto_reload_;
  is_auto_reload_ = on_off;
  return old_flag;
}

auto kratos::util::CsvLoaderImpl::is_auto_reload() -> bool {
  return is_auto_reload_;
}

auto kratos::util::CsvLoaderImpl::get_last_update_timestamp() -> std::time_t {
  return last_update_ts_;
}

auto kratos::util::CsvLoaderImpl::is_modified_since(std::time_t ts) -> bool {
  return (last_update_ts_ >= ts);
}

auto kratos::util::CsvLoaderImpl::row_count() -> std::size_t {
  return row_vec_.size();
}

auto kratos::util::CsvLoaderImpl::get_row(std::size_t row) -> const CsvRow * {
  if (row >= row_vec_.size()) {
    return nullptr;
  }
  return row_vec_.at(row);
}

auto kratos::util::CsvLoaderImpl::get_last_error() -> const std::string & {
  return last_error_;
}

auto kratos::util::CsvLoaderImpl::get_file_path() -> const std::string & {
  return file_path_;
}

auto kratos::util::CsvLoaderImpl::rollback() -> void { new_vec_.clear(); }

auto kratos::util::CsvLoaderImpl::col_count() -> std::size_t { return column_; }

auto kratos::util::CsvLoaderImpl::get_box()->kratos::service::ServiceBox* { return box_; }

auto kratos::util::CsvLoaderImpl::parse(std::istream &is, RowVector *row_vec)
    -> bool {
  std::string field;
  int c = EOF;
  int last_c = EOF;
  bool quote = false;
  bool need_comma = false;
  int col_count = 0;
  int cur_col_count = 0;
  row_vec->clear();
  FieldVector line;
  kratos::service::PoolVector<FieldVector> grid;
  while (!is.eof() && (EOF != (c = is.get()))) {
    if (c == ',') {
      if (quote) {
        // 假设在""内
        field += c;
      } else {
        if (!need_comma) {
          // 字段结束
          line.push_back(kratos::util::trim(field));
          field.assign("");
        }
        if (cur_lineno_ == 1) {
          col_count += 1;
        }
        cur_col_count += 1;
        need_comma = false;
      }
    } else if (c == '\r') {
      if (quote) {
        // 假设在""内
        field += c;
      } else {
        if (is.peek() == '\n') {
          // 行结束
          if (cur_lineno_ == 1) {
            col_count += 1;
          }
          cur_col_count += 1;
          cur_lineno_ += 1;
          c = is.get();
          is.get();
          if (!field.empty()) {
            line.push_back(kratos::util::trim(field));
          }
          grid.push_back(line);
          line.clear();
          field.assign("");
          need_comma = false;
          if (col_count != cur_col_count) {
            // 错误, 列数目不匹配
            save_error("Column mismatch, first column is:" +
                       std::to_string(col_count));
            return false;
          }
          cur_col_count = 0;
        } else {
          // 错误, 结尾格式错误
          save_error("Invalid line end");
          return false;
        }
      }
    } else if (c == '"') {
      if (quote) {
        // 假设在""内
        if ('"' == last_c) {
          // 转义
          field += '"';
        } else {
          // 字段结束, 保留所有字符
          line.push_back(field);
          field.assign("");
          quote = false;
          need_comma = true;
        }
      } else {
        if (need_comma) {
          // 错误, 需要','
          save_error("Need a ','");
          return false;
        }
        field = kratos::util::ltrim(field);
        quote = true;
      }
    } else if (c == '\n') {
      // 忽略
    } else {
      if (need_comma) {
        // 在遇到','前
        if (c != ' ' && c != '\t') {
          // 错误, 只能是空白
          save_error("Invalid format");
          return false;
        }
      } else {
        field.push_back(c);
      }
    }
    last_c = c;
  }
  if (quote) {
    // 错误，未闭合
    save_error("Invalid format, missing \"");
    return false;
  }
  if (!field.empty()) {
    cur_col_count += 1;
    if (col_count != cur_col_count) {
      // 错误, 列数目不匹配
      save_error("Column mismatch, first column is:" +
                 std::to_string(col_count));
      return false;
    }
    line.push_back(kratos::util::trim(field));
  }
  if (!line.empty()) {
    grid.push_back(line);
  }
  for (const auto &line : grid) {
    row_vec->push_back(new CsvRowImpl(line));
  }
  column_ = col_count;
  return true;
}

auto kratos::util::CsvLoaderImpl::save_error(const std::string &error) -> void {
  last_error_ = "[box][csv]";
  last_error_ += "line:" + std::to_string(cur_lineno_) + ",";
  last_error_ += error;
}

kratos::util::CsvRowImpl::CsvRowImpl(const FieldVector &field_vec) {
  field_vec_ = field_vec;
}

kratos::util::CsvRowImpl::~CsvRowImpl() {}

auto kratos::util::CsvRowImpl::get(std::size_t col,
                                   std::string &value) const noexcept -> bool {
  if (field_vec_.empty() || (col >= field_vec_.size())) {
    return false;
  }
  value = field_vec_[col];
  return true;
}

kratos::util::CsvManagerImpl::CsvManagerImpl(kratos::service::ServiceBox *box) {
  box_ = box;
}

kratos::util::CsvManagerImpl::~CsvManagerImpl() {}

auto kratos::util::CsvManagerImpl::start(std::time_t check_interval) -> bool {
  if (!load_all_files()) {
    return false;
  }
  if (check_interval) {
    check_interval_ = check_interval;
  }
  running_ = true;
  worker_ = std::thread([&]() {
    std::vector<CsvLoaderImpl *> updated_loaders;
    std::time_t count_down_tick = check_interval_ * 1000;
    while (running_) {
      if (count_down_tick != 0) {
        count_down_tick -= 100;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        continue;
      }
      count_down_tick = check_interval_ * 1000;
      // 检测文件变化并重载
      for (const auto &[file_name, loader] : loader_map_) {
        if (!loader->is_auto_reload()) {
          // 不允许自动更新
          continue;
        }
        auto file_path = loader->get_file_path();
        auto modify_time = util::get_last_modify_time(file_path);
        auto it = time_map_.find(file_name);
        if (it == time_map_.end()) {
          continue;
        }
        if (modify_time != it->second) {
          if (!loader->load(file_path, 0)) {
            if (box_) {
              std::string error;
              error = "Hot loading CSV file failed, file:" + file_path +
                      loader->get_last_error();
              box_->write_log_line(klogger::Logger::FAILURE, error.c_str());
            }
            // 加载失败
            loader->rollback();
          } else {
            it->second = modify_time;
            updated_loaders.push_back(loader.get());
          }
        }
      }
      for (auto *loader : updated_loaders) {
        // 通知主线程
        update_event_queue_.enqueue(loader);
      }
      updated_loaders.clear();
    }
  });
  return true;
}

auto kratos::util::CsvManagerImpl::stop() -> bool {
  running_ = false;
  if (worker_.joinable()) {
    worker_.join();
  }
  return true;
}

auto kratos::util::CsvManagerImpl::update() -> void {
  CsvLoaderImpl *loader = nullptr;
  while (update_event_queue_.try_dequeue(loader)) {
    loader->check_and_switch();
    for (auto it = listener_map_.begin(); it != listener_map_.end();) {
      if (it->second.handle.expired()) {
        it = listener_map_.erase(it);
      } else {
        try {
          it->second.listener(it->second.file_name, this);
        } catch (std::exception &e) {
          std::string error;
          error = "Unexpected exception when invoking CSV file reload listener "
                  "failed, file:" +
                  loader->get_file_path() + ", Reason:" + e.what();
          box_->write_log_line(klogger::Logger::FAILURE, error.c_str());
        }
        it++;
      }
    }
  }
}

auto kratos::util::CsvManagerImpl::add_listener(const std::string &file_name,
                                                CsvFileChangeListener listener)
    -> ListenerHandle {
  auto ptr = kratos::make_shared_pool_ptr<CsvListenrHandleImpl>();
  listener_map_.emplace(ptr->get_key(), ListenerInfo{file_name, listener, ptr});
  return ptr;
}

auto kratos::util::CsvManagerImpl::remove_listener(ListenerHandle handle)
    -> bool {
  listener_map_.erase(
      std::dynamic_pointer_cast<CsvListenrHandleImpl>(handle)->get_key());
  return false;
}

auto kratos::util::CsvManagerImpl::set_root_directory(
    const std::string &root_dir) -> bool {
  root_dir_ = root_dir;
  return true;
}

auto kratos::util::CsvManagerImpl::set_file_auto_reload(
    const std::string &file_path, bool on_off) -> bool {
  auto it = loader_map_.find(file_path);
  if (it == loader_map_.end()) {
    return false;
  }
  return it->second->set_auto_reload(on_off);
}

auto kratos::util::CsvManagerImpl::new_reader(const std::string &file_name,
    const FieldDescriptor& descriptor)
    -> std::unique_ptr<CsvReader> {
  auto it = loader_map_.find(file_name);
  if (it == loader_map_.end()) {
    return nullptr;
  }
  if (reader_factory_) {
    auto reader =  std::unique_ptr<CsvReader>(
        reader_factory_->create(it->second.get()));
    reader->set_descriptor(descriptor);
    return reader;
  } else {
    auto reader = std::unique_ptr<CsvReader>(
        new CsvReaderDefault(this, it->second.get()));
    reader->set_descriptor(descriptor);
    return reader;
  }
}

auto kratos::util::CsvManagerImpl::new_reader(const std::string& file_name,
    bool use_first_row_as_descriptor) -> std::unique_ptr<CsvReader> {
  auto it = loader_map_.find(file_name);
  if (it == loader_map_.end()) {
      return nullptr;
  }
  FieldDescriptor descriptor;
  if (use_first_row_as_descriptor) {
      const auto* first_row = it->second->get_row(0);
      if (!first_row) {
          return nullptr;
      }
      for (std::size_t col = 0; col < it->second->col_count(); col++) {
          std::string value;
          if (!first_row->get(col, value)) {
              return nullptr;
          }
          descriptor.emplace(value, col);
      }
  }
  if (reader_factory_) {
      auto reader = std::unique_ptr<CsvReader>(
          reader_factory_->create(it->second.get()));
      reader->set_descriptor(descriptor);
      reader->set_skip_line(1);
      return reader;
  }
  else {
      auto reader = std::unique_ptr<CsvReader>(
          new CsvReaderDefault(this, it->second.get()));
      reader->set_descriptor(descriptor);
      reader->set_skip_line(1);
      return reader;
  }
}

auto kratos::util::CsvManagerImpl::set_reader_factory(CsvReaderFactory *factory)
    -> CsvReaderFactory * {
  auto old = reader_factory_;
  reader_factory_ = factory;
  return old;
}

auto kratos::util::CsvManagerImpl::ignore(const std::string &file_name)
    -> void {
  ignore_set_.insert(file_name);
}

auto kratos::util::CsvManagerImpl::load_all_files() -> bool {
  std::vector<std::string> files;
  if (!util::get_file_in_directory(root_dir_, "csv", files)) {
    return false;
  }
  for (const auto &file_path : files) {
    auto file_name = util::get_file_name(file_path) + ".csv";
    if (ignore_set_.find(file_name) != ignore_set_.end()) {
      // 被忽略的文件
      continue;
    }
    auto loader = kratos::make_unique_pool_ptr<CsvLoaderImpl>();
    if (!loader->load(file_path, 0)) {
      if (box_) {
        std::string error;
        error = "Loading CSV file failed, file:" + file_path +
                loader->get_last_error();
        box_->write_log_line(klogger::Logger::FAILURE, error.c_str());
      }
      return false;
    }
    loader_map_[file_name].swap(loader);
    // 记录上一次修改时间
    time_map_.emplace(file_name, kratos::util::get_last_modify_time(file_path));
  }
  return true;
}

kratos::util::CsvListenrHandleImpl::CsvListenrHandleImpl() {
  static std::uint32_t key = 1;
  key_ = key++;
}

kratos::util::CsvListenrHandleImpl::~CsvListenrHandleImpl() {}

auto kratos::util::CsvListenrHandleImpl::get_key() -> std::uint32_t {
  return key_;
}

kratos::util::CsvReaderDefault::CsvReaderDefault(CsvManagerImpl *manager,
                                                 CsvLoaderImpl *loader) {
  manager_ = manager;
  loader_ = loader;
  file_name_ = util::get_file_name(loader->get_file_path()) + ".csv";
  listener_handler_ = manager_->add_listener(file_name_,
    [&](const std::string &file_name, CsvManager *) {
      if (file_name == file_name_) {
        query_cache_.clear();
        row_cache_.clear();
        all_row_.reset(nullptr);
        // 重建索引
        if (!rebuild_index()) {
          // 日志，重建索引失败
          if (loader_->get_box()) {
            loader_->get_box()->write_log(
              lang::LangID::LANG_CSV_REBUILD_INDEX_FAIL,
              klogger::Logger::FAILURE,
              file_name.c_str()
            );
          }
        }
      }
    });
}

kratos::util::CsvReaderDefault::~CsvReaderDefault() {}

auto kratos::util::CsvReaderDefault::get_row() const noexcept -> std::size_t {
  return loader_->row_count();
}

auto kratos::util::CsvReaderDefault::get_column() const noexcept
    -> std::size_t {
  return loader_->col_count();
}

auto kratos::util::CsvReaderDefault::create_index_by_type(
    std::size_t col, const std::string &index_name,
    const std::type_info *type_info) noexcept -> bool {
  for (auto &i : index_vector_) {
    if (index_name == i.index_name) {
      return false;
    }
    if (col == i.column) {
      // 更新名字和类型
      i.index_name = index_name;
      i.type_info = const_cast<std::type_info *>(type_info);
      return true;
    }
  }
  SearchCache search_cache;
  for (std::size_t row = skip_line_; (skip_line_ <= loader_->row_count()) && (row < loader_->row_count()); row++) {
    const auto *row_ptr = loader_->get_row(row);
    std::string value;
    if (!row_ptr->get(col, value)) {
      return false;
    }
    auto &row_vec = search_cache[value];
    row_vec.emplace_back(row_ptr);
  }
  for (auto &[k, v] : search_cache) {
    std::sort(v.begin(), v.end());
  }
  index_vector_.emplace_back(Index{
      index_name, col, const_cast<std::type_info *>(type_info), search_cache});
  return true;
}

auto kratos::util::CsvReaderDefault::find_all() noexcept
    -> const Result & {
  return get_all();
}

auto cast_to_string_key(const std::any &any) -> std::string {
  if (any.type() == typeid(std::string)) {
    return std::any_cast<std::string>(any);
  } else if (any.type() == typeid(const char *)) {
    return std::any_cast<const char *>(any);
  } else if (any.type() == typeid(signed int)) {
    return std::to_string(std::any_cast<signed int>(any));
  } else if (any.type() == typeid(signed short)) {
    return std::to_string(std::any_cast<signed short>(any));
  } else if (any.type() == typeid(signed long)) {
    return std::to_string(std::any_cast<signed long>(any));
  } else if (any.type() == typeid(signed long long)) {
    return std::to_string(std::any_cast<signed long long>(any));
  } else if (any.type() == typeid(unsigned int)) {
    return std::to_string(std::any_cast<unsigned int>(any));
  } else if (any.type() == typeid(unsigned short)) {
    return std::to_string(std::any_cast<unsigned short>(any));
  } else if (any.type() == typeid(unsigned long)) {
    return std::to_string(std::any_cast<unsigned long>(any));
  } else if (any.type() == typeid(unsigned long long)) {
    return std::to_string(std::any_cast<unsigned long long>(any));
  } else {
    return "";
  }
}

auto kratos::util::CsvReaderDefault::find(
    std::initializer_list<CsvQuery> query) noexcept -> const Result & {
  if (query.size() == 0) {
    return get_all();
  }
  if (query.size() > index_vector_.size()) {
    return NullResult;
  }
  std::string query_index;
  for (const auto &key : query) {
    query_index += cast_to_string_key(key.key);
  }
  auto it = query_cache_.find(query_index);
  if (it != query_cache_.end()) {
    return it->second;
  }
  std::vector<const CsvRow *> result;
  std::vector<const CsvRow *> temp;
  std::size_t i = 0;
  for (const auto &key : query) {
    result.clear();
    const auto &index = index_vector_[i++];
    if (index.index_name != key.index_name) {
      continue;
    }
    // if (*index.type_info != key.key.type()) {
    //    // 类型不匹配
    //  return NullResult;
    //}
    auto it = index.search_cache.find(cast_to_string_key(key.key));
    if (it == index.search_cache.end()) {
      return NullResult;
    }
    if (temp.empty()) {
      temp = it->second;
    } else {
      std::set_intersection(temp.begin(), temp.end(), it->second.begin(),
                            it->second.end(), std::back_inserter(result));
      temp.swap(result);
    }
  }
  if (!temp.empty() && result.empty()) {
    temp.swap(result);
  }
  SearchResult search_result;
  for (const auto *row : result) {
    kratos::service::PoolVector<std::string> value_vec;
    for (std::size_t n = 0; n < loader_->col_count(); n++) {
      std::string value;
      row->get(n, value);
      value_vec.emplace_back(value);
    }
    search_result.emplace_back(value_vec);
  }
  ResultImpl return_result(this, std::move(search_result), true);
  auto insert_result =
      query_cache_.emplace(query_index, std::move(return_result));
  return insert_result.first->second;
}

auto kratos::util::CsvReaderDefault::find(
    std::initializer_list<std::any> query_key) noexcept -> const Result & {
  if (query_key.size() == 0) {
    return get_all();
  }
  if (query_key.size() > index_vector_.size()) {
    return NullResult;
  }
  std::string query_index;
  for (const auto &key : query_key) {
    query_index += cast_to_string_key(key) + ".";
  }
  auto it = query_cache_.find(query_index);
  if (it != query_cache_.end()) {
    return it->second;
  }
  std::vector<const CsvRow *> result;
  std::vector<const CsvRow *> temp;
  std::size_t i = 0;
  for (const auto &key : query_key) {
    result.clear();
    const auto &index = index_vector_[i++];
    auto it = index.search_cache.find(cast_to_string_key(key));
    if (it == index.search_cache.end()) {
      return NullResult;
    }
    if (temp.empty()) {
      temp = it->second;
    } else {
      std::set_intersection(temp.begin(), temp.end(), it->second.begin(),
                            it->second.end(), std::back_inserter(result));
      temp.swap(result);
    }
  }
  if (!temp.empty() && result.empty()) {
    temp.swap(result);
  }
  SearchResult search_result;
  for (const auto *row : result) {
    kratos::service::PoolVector <std::string> value_vec;
    for (std::size_t n = 0; n < loader_->col_count(); n++) {
      std::string value;
      row->get(n, value);
      value_vec.emplace_back(value);
    }
    search_result.emplace_back(value_vec);
  }
  ResultImpl return_result(this, std::move(search_result), true);
  auto insert_result =
      query_cache_.emplace(query_index, std::move(return_result));
  return insert_result.first->second;
}

auto kratos::util::CsvReaderDefault::get(std::size_t row) noexcept
    -> const Result & {
  const auto *row_ptr = loader_->get_row(skip_line_ + row);
  if (!row_ptr) {
    return NullResult;
  }
  auto it = row_cache_.find(row);
  if (it != row_cache_.end()) {
    return it->second;
  }
  StringVector sv;
  for (std::size_t i = 0; i < loader_->col_count(); i++) {
    std::string value;
    row_ptr->get(i, value);
    sv.emplace_back(std::move(value));
  }
  ResultImpl result(this, std::move(SearchResult{sv}), true);
  auto insert_result = row_cache_.emplace(row, std::move(result));
  return insert_result.first->second;
}

auto kratos::util::CsvReaderDefault::get(std::size_t row, std::size_t col,
                                         std::string &value) noexcept -> bool {
  auto *row_inst = loader_->get_row(skip_line_ + row);
  if (!row_inst) {
    std::stringstream ss;
    ss << "row:" << row << ",col:" << col << " not found";
    last_error_ = ss.str();
    return false;
  }
  return row_inst->get(col, value);
}

auto kratos::util::CsvReaderDefault::get(
    std::size_t row, std::size_t col, std::vector<std::string> &value) noexcept
    -> bool {
  std::string str;
  if (!get(row, col, str)) {
    return false;
  }
  // a;b;c;d
  util::split(str, ";", value);
  return true;
}

auto kratos::util::CsvReaderDefault::get(
    std::size_t row, std::size_t col,
    std::unordered_map<std::string, std::string> &value) noexcept -> bool {
  std::string str;
  if (!get(row, col, str)) {
    return false;
  }
  // a:b;c:d
  std::vector<std::string> array_result;
  std::vector<std::string> kv_result;
  util::split(str, ";", array_result);
  for (const auto &kv : array_result) {
    kv_result.clear();
    util::split(kv, ":", kv_result);
    if (kv_result.size() != 2) {
      std::stringstream ss;
      ss << "row:" << row << ",col:" << col << ", Map field format invalid";
      last_error_ = ss.str();
      return false;
    }
    value.emplace(kv_result[0], kv_result[1]);
  }
  return true;
}

auto kratos::util::CsvReaderDefault::get(
    std::size_t row, std::size_t col,
    std::unordered_set<std::string> &value) noexcept -> bool {
  std::string str;
  if (!get(row, col, str)) {
    return false;
  }
  std::vector<std::string> result;
  // a:b:c:d
  util::split(str, ":", result);
  for (const auto &k : result) {
    value.emplace(k);
  }
  return true;
}

auto kratos::util::CsvReaderDefault::get(
    std::size_t row, std::size_t col,
    std::map<std::string, std::string> &value) noexcept -> bool {
  std::string str;
  if (!get(row, col, str)) {
    return false;
  }
  // a:b;c:d
  std::vector<std::string> array_result;
  std::vector<std::string> kv_result;
  util::split(str, ";", array_result);
  for (const auto &kv : array_result) {
    kv_result.clear();
    util::split(kv, ":", kv_result);
    if (kv_result.size() != 2) {
      std::stringstream ss;
      ss << "row:" << row << ",col:" << col << ", Map field format invalid";
      last_error_ = ss.str();
      return false;
    }
    value.emplace(kv_result[0], kv_result[1]);
  }
  return true;
}

auto kratos::util::CsvReaderDefault::get(std::size_t row, std::size_t col,
                                         std::set<std::string> &value) noexcept
    -> bool {
  std::string str;
  if (!get(row, col, str)) {
    return false;
  }
  std::vector<std::string> result;
  // a:b:c:d
  util::split(str, ":", result);
  for (const auto &k : result) {
    value.emplace(k);
  }
  return true;
}

auto kratos::util::CsvReaderDefault::get_last_error() noexcept
    -> const std::string & {
  return last_error_;
}

auto kratos::util::CsvReaderDefault::rebuild_index() noexcept -> bool {
  for (auto &index : index_vector_) {
    index.search_cache.clear();
    for (std::size_t row = 0; (skip_line_ <= loader_->row_count()) && (row < loader_->row_count()); row++) {
      const auto *row_ptr = loader_->get_row(row);
      std::string value;
      if (!row_ptr->get(index.column, value)) {
        // 删除了列
        return false;
      }
      auto &row_vec = index.search_cache[value];
      row_vec.emplace_back(row_ptr);
    }
    for (auto &[k, v] : index.search_cache) {
      std::sort(v.begin(), v.end());
    }
  }
  return true;
}

auto kratos::util::CsvReaderDefault::set_descriptor(const FieldDescriptor& descriptor) -> void {
    descriptor_ = descriptor;
}

auto kratos::util::CsvReaderDefault::get_all() noexcept -> const Result & {
  if (!all_row_) {
    SearchResult result;
    for (std::size_t row = skip_line_; (skip_line_ <= loader_->row_count()) && (row < loader_->row_count()); row++) {
      result.emplace_back(std::move(StringVector()));
      const auto *row_ptr = loader_->get_row(row);
      for (std::size_t col = 0; col < loader_->col_count(); col++) {
        std::string value;
        row_ptr->get(col, value);
        result[row - skip_line_].emplace_back(value);
      }
    }
    all_row_.reset(new ResultImpl(this, std::move(result), true));
  }
  return *all_row_;
}

auto kratos::util::CsvReaderDefault::get_descriptor() const -> const FieldDescriptor& {
    return descriptor_;
}

auto kratos::util::CsvReaderDefault::set_skip_line(std::size_t skip_line) const -> void {
    const_cast<CsvReaderDefault*>(this)->skip_line_ = skip_line;
}

kratos::util::ResultImpl::ResultImpl(CsvReaderDefault* reader, SearchResult &&search_result,
                                     bool success) {
  reader_ = reader;
  search_result_ = search_result;
  success_ = success;
  cursor_ = make_unique_pool_ptr<CursorImpl>(this);
}

kratos::util::ResultImpl::ResultImpl(ResultImpl &&rht) noexcept {
  reader_ = rht.reader_;
  search_result_ = std::move(rht.search_result_);
  success_ = rht.success_;
  cursor_.swap(rht.cursor_);
  cursor_->set_result(this);
}

auto kratos::util::ResultImpl::get_cursor() const noexcept -> const Cursor & {
  if (!success_) {
    return NullCursor;
  }
  cursor_->reset();
  cursor_->set_descriptor(&reader_->get_descriptor());
  return *cursor_;
}

auto kratos::util::ResultImpl::get_row() const -> std::size_t {
  return search_result_.size();
}

auto kratos::util::ResultImpl::get_col() const -> std::size_t {
  if (search_result_.empty()) {
    return 0;
  }
  return search_result_[0].size();
}

kratos::util::ResultImpl::operator bool() const { return success_; }

auto kratos::util::ResultImpl::get_search_result() const
    -> const SearchResult & {
  return search_result_;
}

auto kratos::util::ResultImpl::clear() -> void {
  search_result_.clear();
  cursor_->reset();
  success_ = true;
}

kratos::util::CursorImpl::CursorImpl(ResultImpl *result) { result_ = result; }

kratos::util::CursorImpl::~CursorImpl() {}

auto kratos::util::CursorImpl::row_count() const noexcept -> std::size_t {
  if (!result_) {
    return 0;
  }
  return result_->get_row();
}

auto kratos::util::CursorImpl::column() const noexcept -> std::size_t {
  if (!result_) {
    return 0;
  }
  return result_->get_col();
}

auto kratos::util::CursorImpl::has_next() const noexcept -> bool {
  if (!result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  return true;
}

auto kratos::util::CursorImpl::next() const -> void {
  if (!result_) {
    return;
  }
  const_cast<CursorImpl *>(this)->cur_index_ += 1;
}

kratos::util::CursorImpl::operator bool() const { return (result_ != nullptr); }

auto kratos::util::CursorImpl::get(std::size_t col,
                                   std::string &value) const noexcept -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  value = row[col];
  return true;
}

auto kratos::util::CursorImpl::get(
    std::size_t col, std::vector<std::string> &value) const noexcept -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  // a;b;c;d
  util::split(row[col], ";", value);
  return true;
}

auto kratos::util::CursorImpl::get(
    std::size_t col,
    std::unordered_map<std::string, std::string> &value) const noexcept
    -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  // a:b;c:d
  std::vector<std::string> array_result;
  std::vector<std::string> kv_result;
  util::split(row[col], ";", array_result);
  for (const auto &kv : array_result) {
    kv_result.clear();
    util::split(kv, ":", kv_result);
    if (kv_result.size() != 2) {
      return false;
    }
    value.emplace(kv_result[0], kv_result[1]);
  }
  return true;
}

auto kratos::util::CursorImpl::get(
    std::size_t col, std::unordered_set<std::string> &value) const noexcept
    -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  std::vector<std::string> result;
  // a:b:c:d
  util::split(row[col], ":", result);
  for (const auto &k : result) {
    value.emplace(k);
  }
  return true;
}

auto kratos::util::CursorImpl::get(
    std::size_t col, std::map<std::string, std::string> &value) const noexcept
    -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  // a:b;c:d
  std::vector<std::string> array_result;
  std::vector<std::string> kv_result;
  util::split(row[col], ";", array_result);
  for (const auto &kv : array_result) {
    kv_result.clear();
    util::split(kv, ":", kv_result);
    if (kv_result.size() != 2) {
      return false;
    }
    value.emplace(kv_result[0], kv_result[1]);
  }
  return true;
}

auto kratos::util::CursorImpl::get(std::size_t col,
                                   std::set<std::string> &value) const noexcept
    -> bool {
  if (!result_ || !*result_) {
    return false;
  }
  if (cur_index_ >= result_->get_search_result().size()) {
    return false;
  }
  const auto &row = result_->get_search_result()[cur_index_];
  if (col >= row.size()) {
    return false;
  }
  std::vector<std::string> result;
  // a:b:c:d
  util::split(row[col], ":", result);
  for (const auto &k : result) {
    value.emplace(k);
  }
  return true;
}

void kratos::util::CursorImpl::reset() const { const_cast<CursorImpl*>(this)->cur_index_ = 0; }

auto kratos::util::CursorImpl::set_descriptor(const FieldDescriptor* descriptor) -> void {
    descriptor_ = descriptor;
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::string& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::vector<std::string>& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::unordered_map<std::string, std::string>& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::unordered_set<std::string>& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::map<std::string, std::string>& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

auto kratos::util::CursorImpl::get(const std::string& field_name,
    std::set<std::string>& value) const noexcept -> bool {
    if (!descriptor_) {
        return false;
    }
    auto it = descriptor_->find(field_name);
    if (it == descriptor_->end()) {
        return false;
    }
    auto col = it->second;
    return get(col, value);
}

void kratos::util::CursorImpl::set_result(ResultImpl *result) {
  result_ = result;
}
